home *** CD-ROM | disk | FTP | other *** search
- #include <limits.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <pwd.h>
- #include <grp.h>
- #include <sys/stat.h>
- #include <string.h>
- #include <stdio.h>
- #include "fstab.h"
- #include "../userconf/userconf.h"
- #include "../misc/misc.h"
- #include "../netconf/netconf.h"
- #include "../paths.h"
- #include "fstab.m"
-
- /* #Specification: fixperm / strategy
- The directory /usr/lib/linuxconf/conf.permissions contains
- files describing the permissions of different packages.
- The format of the file is rather simple.
-
- #
- filespec owner group type permissions options ...
- #
-
- The permissions are expressed in octal.
-
- type is one of those:
-
- #
- b,major,minor: block device
- c,major,minor: character device
- f: file
- d: directory
- #
-
- Here are the options supported
-
- #
- boot: The check is done only at boot time. This is
- especially intended for pseudo tty which need
- special permissions. Those pty generally change
- while the system is running. Normally, everything
- is back to normal when the system goes down, except
- when it crash. Unless the permissions are set
- correctly, everything goes wrong: Debuggers, some
- editors etc...
- recurse: filespec must be a directory. The
- owner, group and permissions will be
- applied to all file in that directory
- and sudirectory.
- required: The file has to be there. An error
- will be signaled if not. If the file
- is a directory, it will be created.
- #
- */
- #
- const int maxopt=3;
- struct SPEC_ONE{
- const char *fpath; // Path of the specification file
- int noline; // Current line in fpath
- char path[PATH_MAX];
- char owner[PATH_MAX];
- char group[PATH_MAX];
- char type[PATH_MAX];
- int perm;
- char opts[maxopt][PATH_MAX];
- };
-
- /*
- Print an error message with reference to the specification file
- */
- static void fixperm_error (SPEC_ONE &sp, const char *msg, ...)
- {
- va_list list;
- va_start (list,msg);
- char buf[1000];
- vsprintf (buf,msg,list);
- va_end (list);
- xconf_error (MSG_U(E_CONFFILE,"%s\n\n"
- "In file %s, line %d\n"),buf,sp.fpath,sp.noline);
- }
-
-
-
- struct FIXPERM_OPTIONS{
- bool boot;
- bool recurse;
- bool required;
- };
-
- enum FPERM_TYPE { FPERM_FILE, FPERM_DIR};
-
- class FIXPERM_SPEC: public ARRAY_OBJ{
- friend class FIXPERM_SPECS;
- SSTRING path;
- SSTRING owner;
- SSTRING group;
- FPERM_TYPE type;
- int perm;
- int dev;
- FIXPERM_OPTIONS opts;
- int uid;
- int gid;
- bool valid; // Is this record valid
- /*~PROTOBEG~ FIXPERM_SPEC */
- public:
- FIXPERM_SPEC (SPEC_ONE&sp);
- int check (void);
- int create (void);
- private:
- void parsedev (SPEC_ONE&sp);
- public:
- /*~PROTOEND~ FIXPERM_SPEC */
- };
- /*
- Parse the option of one spec
- */
- static int fixperm_parseopts (SPEC_ONE &sp, FIXPERM_OPTIONS &opts)
- {
- int ret = 0;
- opts.boot = opts.recurse = opts.required = false;
- for (int i=0; i<maxopt; i++){
- if (sp.opts[i][0] == '\0'){
- break;
- }else if (strcmp(sp.opts[i],"recurse")==0){
- opts.recurse = true;
- }else if (strcmp(sp.opts[i],"required")==0){
- opts.required = true;
- }else if (strcmp(sp.opts[i],"boot")==0){
- opts.boot = true;
- }else{
- ret = -1;
- fixperm_error (sp,MSG_U(E_IVLDOPT,"Invalid option %s")
- ,sp.opts[i]);
- }
- }
- return ret;
- }
- /*
- Parse a special device spec (b|c,major,minor)
- Return -1 if any error or the encoded device number.
- */
- PRIVATE void FIXPERM_SPEC::parsedev (SPEC_ONE &sp)
- {
- dev = -1;
- const char *type = sp.type + 2;
- if (isdigit(type[0])){
- int major = atoi (type);
- type = str_skipdig(type);
- if (type[0] == ',' && isdigit(type[1])){
- int minor = atoi(type+1);
- dev = major*256 + minor;
- }
- }
- if (dev == -1){
- fixperm_error (sp,MSG_U(E_IVLDDEV
- ,"Invalid device specification\n"
- "Expect b|c,major,minor, got %s\n"),sp.type);
- }
- }
-
-
- PUBLIC FIXPERM_SPEC::FIXPERM_SPEC(SPEC_ONE &sp)
- {
- path.setfrom(sp.path);
- owner.setfrom (sp.owner);
- group.setfrom (sp.group);
- perm = sp.perm;
- dev = 0;
- valid = true;
- if (strcmp(sp.type,"d")==0){
- perm |= S_IFDIR;
- }else if (strcmp(sp.type,"f")==0){
- perm |= S_IFREG;
- }else if (strncmp(sp.type,"c,",2)==0){
- perm |= S_IFCHR;
- parsedev (sp);
- }else if (strncmp(sp.type,"b,",2)==0){
- perm |= S_IFBLK;
- parsedev (sp);
- }else{
- fixperm_error (sp,MSG_U(E_IVLDTYPE
- ,"Invalid type field \"%s\" (b, c, d or f expected)\n")
- ,sp.type);
- valid = false;
- }
- if (fixperm_parseopts(sp,opts)==-1){
- valid = false;
- }
- struct passwd *p = getpwnam (sp.owner);
- struct group *g = getgrnam (sp.group);
- uid = gid = 0;
- if (p == NULL){
- fixperm_error (sp,MSG_U(E_NOUSER
- ,"No user \"%s\" defined on this system")
- ,sp.owner);
- valid = false;
- }else{
- uid = p->pw_uid;
- }
- if (g == NULL){
- fixperm_error (sp,MSG_U(E_NOGROUP
- ,"No group \"%s\" defined on this system")
- ,sp.group);
- valid = false;
- }else{
- gid = g->gr_gid;
- }
- }
-
- #if 0
- PUBLIC void FIXPERM_SPEC::print (FILE *fout)
- {
- fprintf (fout,"%s %s %s %o"
- ,path.get(),owner.get(),group.get(),perm);
- if (opts.recurse) fputs (" recurse",fout);
- if (opts.required) fputs (" required",fout);
- fputc ('\n',fout);
- }
-
- #endif
-
- /*
- Create an empty file or directory
- Return -1 if any error.
- */
- PUBLIC int FIXPERM_SPEC::create()
- {
- int ret = 0;
- const char *fpath = path.get();
- if (S_ISDIR(perm)){
- ret = mkdir (fpath,0666);
- }else if (S_ISCHR(perm) || S_ISBLK(perm)){
- ret = mknod (fpath,perm,dev);
- }else{
- int fd = creat (fpath,O_WRONLY);
- if (fd != -1){
- close(fd);
- }else{
- ret = -1;
- }
- }
- if (ret != 0
- || chown (fpath,uid,gid) == -1
- || chmod (fpath,perm) == -1){
- ret = -1;
- }
- return ret;
- }
-
- /*
- Fix one file specification
- */
- PUBLIC int FIXPERM_SPEC::check()
- {
- if (valid){
- bool dook = !simul_ison();
- struct stat st;
- const char *fpath = path.get();
- if (stat(fpath,&st)==-1){
- /* #Specification: fixperm / symbolic links
- Symbolic links are often used to move things
- around in different file systems. The symbolic
- links are faking the original hierarchy. This complicates
- life for the "fixperm" functionnality of linuxconf.
- In fact, in different time, linuxconf can't produce
- a reliable status.
-
- For example my mail spool directory is on an NFS server.
- Instead of mounting the server spool in /var/spool/mail,
- I use the amd automounter and set a symbolic links like
- this.
-
- ln -s /n/server/var/spool/mail /var/spool/mail
-
- Unfortunatly, linuxconf can't test the validity
- of /var/spool/mail until the network is up. This
- checking is annoying. It complains that /var/spool/mail
- is not a directory and so on.
-
- So here is the patch. If a "something" has been
- replaced by a symbolic links and the destination
- of the link appears to be missing, linuxconf
- won't complain at all.
- */
- if (opts.required && lstat(fpath,&st)==-1){
- net_prtlog (MSG_U(L_CREATING
- ,"Creating %s %s\n")
- ,S_ISDIR(perm)
- ? MSG_U(L_DIRECTORY,"directory")
- : MSG_U(L_FILE,"file")
- ,fpath);
- if (dook) create();
- }
- }else if ((st.st_mode & S_IFMT)
- != (perm & S_IFMT)){
- net_prtlog (
- MSG_U(E_CANTCHG
- ,"**** Can't change the type of file %s\n"
- " manual action required!\n")
- ,fpath);
- }else if ((S_ISBLK(perm) || S_ISCHR(perm))
- && st.st_rdev != dev){
- net_prtlog (MSG_U(E_WRONGDEV,"Device file %s wrongly created\n"
- "\tExpected major %d, minor %d\n"
- "\tFound major %d, minor %d\n"
- "\tManual action required\n")
- ,fpath,dev>>8,dev&0xff,st.st_rdev>>8,st.st_rdev&0xff);
- }else{
- if (st.st_uid != uid
- || st.st_gid != gid){
- if (dook) chown (fpath,uid,gid);
- net_prtlog (MSG_U(L_CHGOWN,"Changing owner of file %s "
- "to %s.%s\n")
- ,fpath,owner.get(),group.get());
- stat(fpath,&st);
- }
- if (st.st_mode != perm){
- if (dook) chmod (fpath,perm);
- net_prtlog (MSG_U(L_CHGPERM
- ,"Changing permissions of file %s "
- "from %o to %o\n")
- ,fpath,st.st_mode,perm);
- }
- }
- }
- return 0;
- }
-
- class FIXPERM_SPECS: public ARRAY{
- /*~PROTOBEG~ FIXPERM_SPECS */
- public:
- FIXPERM_SPECS (const char *fname);
- int check (bool boottime);
- int check (void);
- FIXPERM_SPEC *getitem (int no);
- /*~PROTOEND~ FIXPERM_SPECS */
- };
-
- /*
- Check and optionnally ajust permissions on some files
- */
- PUBLIC FIXPERM_SPECS::FIXPERM_SPECS(const char *fname)
- {
- SPEC_ONE sp;
- sp.fpath = fname;
- sp.noline = 1;
- FILE *fin = xconf_fopen (sp.fpath,"r");
- char buf[500];
- /* #Specification: fixperm / file format / comments
- The fixperm's spec file may contain blank lines and
- line beginning with a # are comments.
- */
- while (fgets (buf,sizeof(buf)-1,fin)!=NULL){
- strip_end (buf);
- char *ptbuf = str_skip(buf);
- if (ptbuf[0] != '\0' && ptbuf[0] != '#'){
- sp.opts[0][0] = sp.opts[1][0] = sp.opts[2][0] = '\0';
- if (sscanf(buf,"%s %s %s %s %o %s %s %s\n"
- ,sp.path,sp.owner,sp.group,sp.type,&sp.perm
- ,sp.opts[0],sp.opts[1],sp.opts[2]) < 5){
- fixperm_error (sp,MSG_U(E_IVLDLINE,"Invalid line"));
- }else{
- add (new FIXPERM_SPEC (sp));
- }
- sp.noline++;
- }
- }
- }
-
-
- PUBLIC FIXPERM_SPEC *FIXPERM_SPECS::getitem(int no)
- {
- return (FIXPERM_SPEC*)ARRAY::getitem(no);
- }
-
- PUBLIC int FIXPERM_SPECS::check(bool boottime)
- {
- int ret = 0;
- for (int i=0; i<getnb(); i++){
- FIXPERM_SPEC *chk = getitem(i);
- /* #Specification: fixperm / boot time check
- Some checking is done only at boot time
- because permission and ownership change while
- working. This is especially true for pty's.
- */
- if (chk->opts.boot){
- if (boottime){
- if (chk->check() == -1) ret = -1;
- }
- }else{
- if (chk->check() == -1) ret = -1;
- }
- }
- return ret;
- }
-
- PUBLIC int FIXPERM_SPECS::check()
- {
- return check (false);
- }
-
-
- static int fixperm_check (
- const char *prefix,
- SSTRINGS &lst,
- bool boottime)
- {
- int ret = 0;
- for (int i=0; i<lst.getnb(); i++){
- const char *ptf = lst.getitem(i)->get();
- if (ptf[0] != '\0'){
- char path[PATH_MAX];
- sprintf (path,"%s/%s",prefix,ptf);
- FIXPERM_SPECS specs(path);
- if (specs.check(boottime) == -1) ret = -1;
- }
- }
- return ret;
- }
-
-
- /*
- Check and optionnally ajust permissions on some files
-
- Return -1 if any error.
- */
- static int fixperm_check(bool boottime)
- {
- /* #Specification: fixperm / /var/lib/conf.permissions / strategy
- Linuxconf provide its own set of permissions files
- int /usr/lib/linuxconf/conf.permissions. These are
- supplied with linuxconf and will probably get updated
- at each new releases.
-
- You can create permission files in /var/lib/conf.permissions.
- If you create a permission file with the same name as
- one in /usr/lib/linuxconf/conf.permissions, yours will
- take precedence. This allows you to do customisation
- of those file without fearing the next update :-)
- */
- SSTRINGS usr_tb;
- dir_getlist(USR_LIB_CONF_PERMISSIONS,usr_tb);
- SSTRINGS var_tb;
- dir_getlist(VAR_LIB_CONF_PERMISSIONS,var_tb);
- for (int v=0; v<var_tb.getnb(); v++){
- int u = usr_tb.lookup(var_tb.getitem(v));
- if (u != -1) usr_tb.getitem(u)->setfrom("");
- }
- return fixperm_check (USR_LIB_CONF_PERMISSIONS,usr_tb,boottime)
- | fixperm_check (VAR_LIB_CONF_PERMISSIONS,var_tb,boottime);
- }
- /*
- Check and optionnally ajust permissions on some files
-
- Return -1 if any error.
- */
- int fixperm_check()
- {
- return fixperm_check(false);
- }
- /*
- Check and optionnally ajust permissions on some files at boot time
-
- Return -1 if any error.
- */
- int fixperm_check_boot()
- {
- simul_init();
- int ret = fixperm_check(true);
- if (ret != -1 && simul_prompt()==1){
- ret = fixperm_check(true);
- }
- return ret;
- }
-
- /*
- Check and optionnally ajust permissions on some system
- */
- static int fixperm_check(int nb, char *tb[])
- {
- int ret;
- /* #Specification: fixperm / command line / args
- "fixperm --update" or "fixperm --status" without
- further arguments will check all system in
- /usr/lib/linuxconf/conf.permissions/
- and /var/lib/conf.permissions/.
-
- If some argument are provided, they are taken
- as specific system to check in either
- /usr/lib/linuxconf/conf.permissions/ or
- /var/lib/conf.permissions/.
-
- If one argument start with a /, it is taken as an absolute
- path to a specification file using the same format
- as the ones in /usr/lib/linuxconf/conf.permissions/.
- */
- if (nb == 0){
- ret = fixperm_check(); // Check all
- }else{
- ret = 0;
- SSTRINGS usr_tb;
- dir_getlist(USR_LIB_CONF_PERMISSIONS,usr_tb);
- SSTRINGS var_tb;
- dir_getlist(VAR_LIB_CONF_PERMISSIONS,var_tb);
- for (int i=0; i<nb; i++){
- char *arg = tb[i];
- char path[PATH_MAX];
- if (arg[0] == '/'){
- strcpy (path,arg);
- }else if (var_tb.lookup(arg) !=-1){
- sprintf (path,"%s/%s",VAR_LIB_CONF_PERMISSIONS
- ,arg);
- }else if (usr_tb.lookup(arg) !=-1){
- sprintf (path,"%s/%s",USR_LIB_CONF_PERMISSIONS
- ,arg);
- }
- FIXPERM_SPECS specs(path);
- if (specs.check() == -1) ret = -1;
- }
- }
- return ret;
- }
-
- static void usage()
- {
- fprintf (stderr,
- "fixperm --status\n"
- "fixperm --update [ system ... ]\n"
- );
- }
-
- int fstab_fixperm (int argc, char *argv[])
- {
- int ret = -1;
- if (argc == 1){
- usage();
- }else{
- if (strcmp(argv[1],"--status")==0){
- simul_init(stdout);
- ret = fixperm_check (argc-2,argv+2);
- }else if (strcmp(argv[1],"--update")==0){
- if (perm_rootaccess("set file permissions")){
- net_introlog ("fixperm --update");
- ret = fixperm_check (argc-2,argv+2);
- }else{
- ret = -1;
- }
- }else{
- usage();
- }
- }
- return ret;
- }
-
-